#!/bin/bash

# Reboot immediately if we run the kdump capture kernel
VMCORE_FILE=/proc/vmcore
if [ -e $VMCORE_FILE -a -s $VMCORE_FILE ]; then
   echo "We have a /proc/vmcore, then we just kdump'ed"
   /sbin/reboot
fi

REBOOT_USER=$(logname)
REBOOT_TIME=$(date)
PLATFORM=$(sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
ASIC_TYPE=$(sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type)
DEVPATH="/usr/share/sonic/device"
PLAT_REBOOT="platform_reboot"
REBOOT_CAUSE_FILE="/host/reboot-cause/reboot-cause.txt"
VERBOSE=no
EXIT_NEXT_IMAGE_NOT_EXISTS=4
EXIT_SONIC_INSTALLER_VERIFY_REBOOT=21

function debug()
{
    if [[ x"${VERBOSE}" == x"yes" ]]; then
        echo `date` $@
    fi
    logger "$@"
}

function stop_sonic_services()
{
    if [[ x"$ASIC_TYPE" != x"mellanox" ]]; then
        debug "Stopping syncd process..."
        docker exec -i syncd /usr/bin/syncd_request_shutdown --cold > /dev/null
        sleep 3
    fi
}

function clear_warm_boot()
{
    # If reboot is requested, make sure the outstanding warm-boot is cleared
    # So the system will come up from a cold boot.
    WARM_DIR="/host/warmboot"
    REDIS_FILE=dump.rdb
    TIMESTAMP=`date +%Y%m%d-%H%M%S`
    if [[ -f ${WARM_DIR}/${REDIS_FILE} ]]; then
        mv -f ${WARM_DIR}/${REDIS_FILE} ${WARM_DIR}/${REDIS_FILE}.${TIMESTAMP} || /bin/true
    fi
    /sbin/kexec -u || /bin/true
}

SCRIPT=$0

function show_help_and_exit()
{
    echo "Usage ${SCRIPT} [options]"
    echo "    Request rebooting the device. Invoke platform-specific tool when available."
    echo "    This script will shutdown syncd before rebooting."
    echo " "
    echo "    Available options:"
    echo "        -h, -? : getting this help"

    exit 0
}

function setup_reboot_variables()
{
    NEXT_SONIC_IMAGE=$(sonic-installer list | grep "Next: " | cut -d ' ' -f 2)
    IMAGE_PATH="/host/image-${NEXT_SONIC_IMAGE#SONiC-OS-}"
}

function reboot_pre_check()
{
    # Make sure that the file system is normal: read-write able
    filename="/host/test-`date +%Y%m%d-%H%M%S`"
    ERR=0
    touch ${filename} || ERR=$?
    if [[ ${ERR} -ne 0 ]]; then
        # Continue rebooting in this case, but log the error
        VERBOSE=yes debug "Filesystem might be read-only or full ..."
    fi
    rm ${filename}

    # Verify the next image by sonic_installer
    local message=$(sonic_installer verify-next-image 2>&1)
    if [ $? -ne 0 ]; then
        VERBOSE=yes debug "Failed to verify next image: ${message}"
        exit ${EXIT_SONIC_INSTALLER_VERIFY_REBOOT}
    fi
}

function parse_options()
{
    while getopts "h?v" opt; do
        case ${opt} in
            h|\? )
                show_help_and_exit
                ;;
            v )
                VERBOSE=yes
                ;;
        esac
    done
}

parse_options $@

# Exit if not superuser
if [[ "$EUID" -ne 0 ]]; then
    echo "This command must be run as root" >&2
    exit 1
fi

debug "User requested rebooting device ..."

setup_reboot_variables
reboot_pre_check

# Stop SONiC services gracefully.
stop_sonic_services

clear_warm_boot

# Update the reboot cause file to reflect that user issued 'reboot' command
# Upon next boot, the contents of this file will be used to determine the
# cause of the previous reboot
echo "User issued 'reboot' command [User: ${REBOOT_USER}, Time: ${REBOOT_TIME}]" > ${REBOOT_CAUSE_FILE}
sync
/sbin/fstrim -av
sleep 3

# sync the current system time to CMOS
if [ -x /sbin/hwclock ]; then
    /sbin/hwclock -w || /bin/true
fi

if [ -x ${DEVPATH}/${PLATFORM}/${PLAT_REBOOT} ]; then
    VERBOSE=yes debug "Rebooting with platform ${PLATFORM} specific tool ..."
    exec ${DEVPATH}/${PLATFORM}/${PLAT_REBOOT} $@

    # There are a couple reasons execution reaches here:
    #
    # 1. The vendor platform reboot returned after scheduled the platform specific reboot.
    #    This is a vendor platform reboot code bug but it happens.
    # 2. The vendor platform reboot failed. e.g. due to platform driver didn't load properly.
    #
    # As result if the reboot script reaches here. We should make the reboot happen.
    # Sleep 1 second before calling /sbin/reboot to accommodate situation #1 above.
    sleep 1

    VERBOSE=yes debug "Platform specific reboot failed!" >&2
fi

VERBOSE=yes debug "Issuing OS-level reboot ..." >&2
exec /sbin/reboot $@
